/*
 *  实现一个udp 通讯服务类, 需要接收数据的话只需继承改类即可
 *   2024.4.24  更新ipv6 支持 ，加入组播监听功能
 */
#pragma once
#ifndef __ADEALL_UDP_SERVER_HPP__
#define __ADEALL_UDP_SERVER_HPP__
#include "yade_network.hpp"
#include "mutexlock.hpp"
#include "thread/thread_base.h"

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <queue>

typedef void FunCallBackFuntion(std::string ip, int port, std::vector<uint8_t>, void *);

// udp 接收数据
struct UDP_MSG
{
    std::string cli_ip;
    in_port_t cli_port;
    std::vector<uint8_t> buffer;
    int len;
};

class ADEALL_UDP_SERVER
{

private:
    static void *UDPrevthreadfunAll(void *);
    static void *PrintfInfo(void *);
    static void *Msgthread(void *); // 消息处理线程
    void processMessages();

    MutexLock msg_lock; // 消息队列锁
    MutexLock sendcs;   // 发送锁

    FunCallBackFuntion *_callback;
    void *_context;
    int srv_fd; // 接收fd

    size_t buff_size; // 缓冲区大小
    int thread_max;
    std::queue<UDP_MSG> messages_queue;
    int recv_runing_N; // 正在执行接收解析的线程数

protected:
    virtual void CallBackFuntion(std::string ip, int port, std::vector<uint8_t>, void *);

public:
    ADEALL_UDP_SERVER(/* args */);
    ~ADEALL_UDP_SERVER();

    /*
     * 重新设置接收缓冲区大小，默认1024，一般来说够了，如果数据帧过长时考虑加大这个缓冲器
     * 通常来说，如果你预计会接收大量的数据或者需要处理高流量的网络流量，你可能需要增加接收缓冲区的大小。
     * 但是，设置得太大也可能导致资源浪费或者延迟增加。
     */
    void SetRecvBuffSize(size_t s);

    /**
     * 初始化监听
     *  cliceport 监听端口号
     *  contex 上下文引用,回调函数用
     *  iface 需要绑定的网卡ip
     *  therad_Max 接收解析最大线程数
     *  fun 给定回调函数指针，不指定可以重载 void CallBackFuntion(std::string ip, int port, std::vector<uint8_t>, void *)
     */
    int Init(int cliceport, void *contex, std::string iface = "::", size_t therad_Max = 10, FunCallBackFuntion *fun = nullptr);
    /**
     * 加入组播监听
     * ip 组播地址
     * iface_ip 需要绑定网卡的ip
     */
    int AddMulticast(std::string ip, std::string iface_ip);

    void MessagSend(const char *ip, int port, const char *data, int L, int fd = -1);
    void MessagSend(const char *ip, int port, const std::string data, int fd = -1);

    /*
     * 创建一个可以用于发送数据的fd 在发送数据时可使用默认的init 时创建的fd 也可以使用 另外创建的fd
     * iface 指定网卡ip 默认任意地址
     * cliceport 端口号，可以指定也可以不指定，发送必须通过某个端口，为负数则自动分配一个端口
     */
    static int CreateIpFd(std::string iface = "::", int cliceport = -1);
    /**
     * 封装的一个send函数，轻便化发送数据
     */
    static int UdpSend(const char *ip, int port, const char *data, int L, int send_fd);
    // 获取解析运行线程数
    size_t get_running_N();
    // 获取待处理缓冲区数据个数
    size_t get_msg_N();
};
#endif